/*------------------------------------------------------------------------
|                            FILE DESCRIPTION                            |
------------------------------------------------------------------------*/
/*------------------------------------------------------------------------
|  - File name     : os_task.c
|  - Author        : zeweni
|  - Update date   : 2021.03.25
|  - Copyright(C)  : 2021-2021 zeweni. All rights reserved.
------------------------------------------------------------------------*/
/*------------------------------------------------------------------------
|                            COPYRIGHT NOTICE                            |
------------------------------------------------------------------------*/
/*
 * Copyright (C) 2021, zeweni (17870070675@163.com)

 * This file is part of Ant Real Time Operating System.

 * Ant Real Time Operating System is free software: you can redistribute 
 * it and/or modify it under the terms of the Apache-2.0 License.

 * Ant Real Time Operating System is distributed in the hope that it will 
 * be useful,but WITHOUT ANY WARRANTY; without even the implied warranty 
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * Apache-2.0 License License for more details.

 * You should have received a copy of the Apache-2.0 License.Ant Real Time
 * Operating System. If not, see <http://www.apache.org/licenses/>.
**/
/*------------------------------------------------------------------------
|                                INCLUDES                                |
------------------------------------------------------------------------*/

#include "os_thread.h"
#include "os_mem.h"
#include "os_cpu.h"
#include "os_core.h"

/*------------------------------------------------------------------------
|                                  DATA                                  |
------------------------------------------------------------------------*/

/**
 * @brief   正在运行的线程节点.
 * @details The thread node that is running.
**/
OS_Thread_t *G_OS_Thread_RunNode;

/**
 * @brief     线程就绪链表队列。
 * @details   Thread ready linked list queue.
**/
struct OS_Thread_List G_OS_Thread_RdyList;

/**
 * @brief     线程休眠链表队列。
 * @details   Thread sleep linked list queue.
**/
struct OS_Thread_List G_OS_Thread_SlpList;

/**
 * @brief     线程阻塞链表队列。
 * @details   The thread blocks the linked list queue.
**/
struct OS_Thread_List G_OS_Thread_BlkList;

/**
 * @brief    空闲函数入口句柄地址。
 * @details  RTOS idle task handle function.
**/
OS_Idle_Thread_Handle_t OS_Idle_Excute = OS_NULL;
 
/**
 * @brief   空闲线程的指针句柄。
 * @details The pointer handle of the idle thread.
**/
OS_Thread_t OS_Idle_Thread; 

/**
 * @brief   空闲线程堆栈。
 * @details Idle thread stack.
**/
OS_Thread_Stk Idle_Stack[OS_IDLE_THREAD_STK_SIZE];

/**
 * @brief   线程创建的数量，要小于等于OS_THREAD_MAX_NUM。
 * @details The number of threads created must be less than or equal to OS_THREAD_MAX_NUM.
**/
static os_uint8_t G_Thread_Create_Num;
 
/*------------------------------------------------------------------------
|                              API FUNCTIONS                             |
------------------------------------------------------------------------*/

/**
 * @brief   OS异常处理函数。
 * @details OS exception handling function.
 * @param   excCode 异常代号.Exception code.
 * @return  None.
 * @note    OS运行出现差错时，回调这个异常处理函数，用来指示出现的错误。
 *          When there is an error in the OS operation, 
 *          this exception handling function is called back to indicate the error.
**/
extern void OS_Exce_Handle(os_uint8_t excCode);

/**
 * @brief     获取就绪线程队列链表中优先级最高的线程。
 * @details   Get the thread with the highest priority in the ready thread list.
 * @param[in] maxPriLabel 最高优先级的线程标号。The thread label with the highest priority.
 * @return    [OS_Thread_t]  更新成功,返回最高优先级的地址。 Update completed.
 * @return    [OS_NULL] 更新失败或者就绪线程链表为空。
 *            The update failed or the ready thread list is empty.
**/
OS_Thread_t OS_RdyList_Get_MaxPrio(os_uint8_t *maxPriLabel)
{
	os_uint8_t index = 0;
	os_uint8_t maxPrio = 0;
	
	*maxPriLabel = 0;
	
	for(index = 0; index < G_OS_Thread_RdyList.Num; index++)
	{
		if ( ((OS_Thread_t) *G_OS_Thread_RdyList.Node[index]) -> Prio > maxPrio)
		{
			maxPrio = ((OS_Thread_t) *G_OS_Thread_RdyList.Node[index]) -> Prio;
			*maxPriLabel = index;
		}		
	}
	
	return  G_OS_Thread_RdyList.Node[*maxPriLabel];
}


/**
 * @brief     更新线程链表。
 * @details   Update the thread list.
 * @param     list 链表地址。Linked list address.
 * @return    None.
**/
void OS_Update_List(OS_Thread_t *list)
{
	os_uint8_t index = 0;
	
	switch((*list) -> Status)
	{
		case OS_THREAD_READY:
		{
			(OS_Thread_t *)G_OS_Thread_RdyList.Node[G_OS_Thread_RdyList.Num++] = list;
			return;
		}
		case OS_THREAD_SLEEP:
		{
			for(; index < OS_THREAD_LIST_LEN; index++)
			{
				if(G_OS_Thread_SlpList.Node[index] == OS_NULL)
				{
					(OS_Thread_t *)G_OS_Thread_SlpList.Node[index] = list;
					G_OS_Thread_SlpList.Num++;
					return;
				}
			}
			break;
		}
		case OS_THREAD_BLOCK:
		{
			(OS_Thread_t *)G_OS_Thread_BlkList.Node[G_OS_Thread_BlkList.Num++] = list;
			return;
		}
		default: return;  
	}

}


/**
 * @brief     初始化线程对象。
 * @details   Initialize the thread object.
 * @param[in] thread   线程对象地址。The address of thread object.
 * @param[in] id       线程ID，不可重复。The ID of the thread, cannot be repeated.
 * @param[in] entry    线程入口地址。Thread entry address.
 * @param[in] param    线程入口参数。Thread entry parameters.
 * @param[in] stkAddr  线程堆栈地址。Thread stack address.
 * @param[in] stkSize  线程堆栈大小。Thread stack size.
 * @param[in] slice    线程运行时间片，单位是tick。Thread running time slice, the unit is tick.
 * @return    [OS_OK]  线程初始化成功。 The thread is initialized successfully.
 * @return    [OS_NOK] 线程初始化失败。 The thread initialization failed.
**/
static os_err_t OS_Thread_Init(OS_Thread_t *pthread,
								   OS_Thread_t thread,
					               os_uint8_t id, 
						           void(*entry)(void), 
								   void *param,
								   os_uint8_t priority,
						           os_uint8_t *stkAddr,
						           os_uint8_t stkSize,
                                   os_uint16_t slice)
{
	os_uint8_t num = 0;
	
	*pthread = thread;
	
	if (OS_Object_Init((OS_Object_t *)pthread, id, OS_Object_Class_Thread) != OS_OK) 
	{
		return OS_NOK;
	}	
	
	thread -> Entry = entry;
	thread -> StkAddr = stkAddr;
	thread -> StkSize = stkSize;
	thread -> Prio = priority;
	thread -> TickSlice = slice;
	thread -> SliCtr = slice;
	
	/** 堆栈的底部（首地址）保存数据的长度，被填充到堆栈中。
	    The bottom of the stack holds the length of the data 
	    to be filled in the stack. */
	*(stkAddr++) = 15; /* 15 = 2 (thread entry of function address) + 13 (mcu register data) */

	/** 第二个堆栈字节空间读取任务功能的高8位地址。第三个堆栈字节空间读取任务功能的高8位地址。
     	The second address read task function low 8 bits address.
	    The third address read task function high 8 bits address. */					
	*stkAddr++ = (os_uint16_t)entry;
	*stkAddr = (os_uint16_t)entry >> 8;
	
	/** 首先清除第4个到第16个堆栈字节，此处的位置保存MCU的寄存器值。 
	The fourth to sixteenth stack positions are cleared first,
	 * and the position here is to save MCU registers.	*/
	for(num=0;num<11;num++) *(++stkAddr) = 0;	

	*stkAddr++ = (os_uint32_t)param;   /*!< R3 */
	*stkAddr++ = (os_uint32_t)param >> 8; /*!< R2 */
	*stkAddr = (os_uint32_t)param >> 16; /*!< R1 */

	return OS_OK;
}


/**
 * @brief     静态创建一个线程。成功则返回线程对象的句柄地址。
 * @details   Create a thread, and return the handle address of the thread object if it succeeds.
 * @param[in] thread     线程指针句柄，不可重复。Thread pointer handle, not repeatable.
 * @param[in] thread_id  线程ID，不可重复。The ID of the thread, cannot be repeated.
 * @param[in] entry      线程入口地址。Thread entry address.
 * @param[in] param      线程入口参数。Thread entry parameters.
 * @param[in] priority   线程优先级。Thread priority
 * @param[in] stkAddr    线程堆栈地址。Thread stack address.
 * @param[in] stkSize    线程堆栈大小。Thread stack size.
 * @param[in] slice      线程运行时间片，单位是tick。Thread running time slice, the unit is tick.
 * @return    [OS_Thread_t]  线程初始化成功,返回线程句柄地址。
 *                           The thread is initialized successfully and the address is returned.
 * @return    [OS_NULL]      线程初始化失败。 The thread initialization failed.
 * @note      静态创建线程的方法，用户需要定义一个线程堆栈和线程控制块指针（可选），
 *            指针主要用来做线程控制，比如挂起和删除。
 *            To create a thread statically, 
 *            the user needs to define a thread stack and thread control block pointer (optional),
 *            The pointer is mainly used for thread control, such as suspend and delete.
**/
OS_Thread_t OS_Thread_Create_Static(OS_Thread_t *pthread,
									   os_uint8_t thread_id, 
									   void(*entry)(void),
									   void *param,
									   os_uint8_t priority,
									   OS_Thread_Stk *stkAddr, 
									   os_uint8_t stkSize,
									   os_uint16_t slice)
{
	os_uint8_t index = 0;
	OS_Thread_t thread;
	
    /* RTOS enters the critical area of the system. */		
	if(G_Thread_Create_Num <= OS_THREAD_MAX_NUM)
	{
		OS_ENTER_CRITICAL();
		
		for(index=0; index < G_OS_Thread_RdyList.Num && G_OS_Thread_RdyList.Num > 1; index++)
		{
			if( ((OS_Thread_t) *G_OS_Thread_RdyList.Node[index]) -> Prio == priority )
			{
				OS_Exce_Handle(EXC_CODE_SAME_PRI_THREAD);
			}
		}
		
		thread = OS_Malloc(pthread,sizeof(struct OS_Thread));
		
		if(thread != OS_NULL)
		{
			OS_Thread_Init(pthread, thread, thread_id, entry, param, priority, stkAddr, stkSize, slice);
			
			thread -> Status = OS_THREAD_READY;

			(OS_Thread_t *)G_OS_Thread_RdyList.Node[G_OS_Thread_RdyList.Num++] = pthread;
			
			if(G_OS_Thread_RunNode != OS_NULL) 
			{
				OS_Thread_Schedule();
			}
			
			G_Thread_Create_Num++;
			
			OS_EXIT_CRITICAL();
			
			return thread;
		}
		
		OS_EXIT_CRITICAL();
	}
	
	return OS_NULL;
}


/**
 * @brief     动态创建一个线程。成功则返回线程对象的句柄地址。
 * @details   Create a thread, and return the handle address of the thread object if it succeeds.
 * @param[in] thread     线程指针句柄，不可重复。Thread pointer handle, not repeatable.
 * @param[in] thread_id  线程ID，不可重复。The ID of the thread, cannot be repeated.
 * @param[in] entry      线程入口地址。Thread entry address.
 * @param[in] param      线程入口参数。Thread entry parameters.
 * @param[in] priority   线程优先级。Thread priority
 * @param[in] stkAddr    线程堆栈地址。Thread stack address.
 * @param[in] stkSize    线程堆栈大小。Thread stack size.
 * @param[in] slice      线程运行时间片，单位是tick。Thread running time slice, the unit is tick.
 * @return    [OS_Thread_t]  线程初始化成功,返回线程句柄地址。
 *                           The thread is initialized successfully and the address is returned.
 * @return    [OS_NULL]      线程初始化失败。 The thread initialization failed.
 * @note      动态创建线程的方法，用户需要定义一个线程堆栈指针和线程控制块指针（可选），
 *            指针主要用来做线程控制，比如挂起和删除。
 *            To dynamically create threads, users need to define a thread stack pointer
 *            and thread control block pointer (optional),
 *            The pointer is mainly used for thread control, such as suspend and delete.
**/
OS_Thread_t OS_Thread_Create(OS_Thread_t *pthread,
							    os_uint8_t thread_id, 
							    void(*entry)(void),
							    void *param,
							    os_uint8_t priority,
							    OS_Thread_Stk **stkAddr, 
							    os_uint8_t stkSize,
							    os_uint16_t slice)
{
	*stkAddr = (os_uint8_t *)OS_Malloc(*stkAddr,stkSize);

	return OS_Thread_Create_Static(pthread,
								      thread_id,        
								      entry,
								      param,
								      priority,
								      *stkAddr,
								      stkSize,
								      slice);
}									   
/**
 * @brief     休眠一个线程（只能是自身），被休眠的线程主动让出CPU使用权。
 * @details   When a thread is hibernated, the hibernated thread voluntarily surrenders 
 *            the right to use the CPU.
 * @param[in] ticks 系统节拍数。The number of system beats.
 * @return    [OS_OK]  线程休眠成功。 The thread is sleep successfully.
 * @return    [OS_NOK] 线程休眠失败。 Thread sleep failure.
**/
os_err_t OS_Thread_Sleep(os_uint16_t ticks)
{

	/* RTOS enters the critical area of the system. */	
	OS_ENTER_CRITICAL();
	(*G_OS_Thread_RunNode) -> SlpCtr = ticks;
	(*G_OS_Thread_RunNode) -> Status = OS_THREAD_SLEEP;
	OS_EXIT_CRITICAL();
	OS_Thread_Schedule();
	
	return OS_OK;
}

/**
 * @brief     线程休眠ms函数，单位是ms。
 * @details   The thread delays the ms function, the unit is ms.
 * @param[in] nms ms时间。Ms time.
 * @return    [OS_OK]  线程延时成功。 The thread is delay successfully.
 * @return    [OS_NOK] 线程延时失败。 Thread delay failure.
 * @note      最小ms时间，要>=tick单位时间。
**/
os_err_t OS_Thread_MSleep(os_uint16_t nms)
{
	
	OS_Thread_Sleep(nms/OS_SYS_TICK_UNIT_TIME);
	return OS_OK;
}


/**
 * @brief     空闲线程，用于任务调度，默认被创建。
 * @details   Idle thread, used for task scheduling, is created by default.
 * @param     None.
 * @return    None.
**/
void AntOS_Idle_Thread(void)
{
	for(;;)
	{
		
		/* If user will be use idle task handle function, run it.*/
		if(OS_Idle_Excute) OS_Idle_Excute();
		
	}
}


/**
 * @brief     线程让出CPU使用权，并进入就绪态。
 * @details   The thread gives up the right to use the CPU and enters the ready state.
 * @param     None.
 * @return    [OS_OK]  线程让出成功。 Thread yields successfully.
 * @return    [OS_NOK] 线程让出失败。 Thread yield failure.
 * @note      如果被操作线程优先级在就绪队列中最高，将会被再次调度。
 *            If the priority of the operated thread is the highest in the ready queue, 
 *            it will be scheduled again.
**/
os_err_t OS_Thread_Yield(void)
{
	(*G_OS_Thread_RunNode) -> Status = OS_THREAD_READY;
	OS_Thread_Schedule();
	return OS_OK;
}

/**
 * @brief     挂起一个线程，可以是自身，也可以是其他线程。
 * @details   Suspend a process. This process can be itself or other threads.
 * @param     thread   要被挂起的线程。Thread to be suspended.
 * @return    [OS_OK]  线程挂起成功。 The thread is suspended successfully.
 * @return    [OS_NOK] 线程挂起失败。 The thread suspend failed.
 * @note      如果挂起自身，那么将会触发一次任务调度。
 *            If you suspend itself, it will trigger a task schedule
**/
os_err_t OS_Thread_Suspend(OS_Thread_t *thread)
{
	os_uint8_t index1 = 0;
	os_uint8_t index2 = 0;
	os_bool susCompFlg = OS_FALSE;
	
	OS_ENTER_CRITICAL();
	
	if(thread == OS_THREAD_SELF) thread = G_OS_Thread_RunNode;
	
	switch((*thread) -> Status)
	{
		case OS_THREAD_READY:
		{					
			/** 删除链表节点。Delete linked list node. */
			for(index1 = 0; index1 < OS_THREAD_MAX_NUM; index1++)
			{
				if(thread == (OS_Thread_t *)G_OS_Thread_RdyList.Node[index1])
				{
					G_OS_Thread_RdyList.Node[index1] = \
					G_OS_Thread_RdyList.Node[--G_OS_Thread_RdyList.Num];
					G_OS_Thread_RdyList.Node[G_OS_Thread_RdyList.Num] = OS_NULL;
					susCompFlg = OS_TRUE;
					break;
				}
			}
			break;
		}
		case OS_THREAD_SLEEP:
		{
			/** 删除链表节点。Delete linked list node. */
			for(index1 = 0; index1 < OS_THREAD_MAX_NUM; index1++)
			{
				if(thread == (OS_Thread_t *)G_OS_Thread_SlpList.Node[index1])
				{
					
					for(index2 = index1; index2 < OS_THREAD_MAX_NUM; index2++)
					{
						if(G_OS_Thread_SlpList.Node[index2] != OS_NULL)
						{
							G_OS_Thread_SlpList.Node[index1] = G_OS_Thread_SlpList.Node[index2];
							G_OS_Thread_SlpList.Node[index2] = OS_NULL;
							G_OS_Thread_SlpList.Num--;
							susCompFlg = OS_TRUE;
							break;							
						}
					}

				}
			}
			break;
		}
		case OS_THREAD_RUNNING:
		{
			G_OS_Thread_RunNode = OS_NULL;
			susCompFlg = OS_TRUE;
			break;
		}
		default: break;
	}	
	
	if(susCompFlg == OS_TRUE)
	{
		(*thread) -> Status = OS_THREAD_BLOCK;
		
		if(thread == OS_THREAD_SELF) 
		{
			OS_Thread_Schedule();
		}
		else
		{
			OS_Update_List(thread);
		}
		OS_EXIT_CRITICAL();
		return OS_OK;
	}

	OS_EXIT_CRITICAL();
	return OS_NOK;
}


/**
 * @brief     恢复一个线程，不可以是自身，只能是其他线程。
 * @details   Resume a process. This process can be itself or other threads.
 * @param[in] thread   要被恢复线程。Thread to be resumed.
 * @return    [OS_OK]  线程恢复成功。 The thread is resumeed successfully.
 * @return    [OS_NOK] 线程恢复失败。 The thread resume failed.
**/
os_err_t OS_Thread_Resume(OS_Thread_t *thread)
{
	os_uint8_t index = 0;
	
	OS_ENTER_CRITICAL();
	
	if(thread == G_OS_Thread_RunNode) return OS_NOK;

	for(index = 0; index < G_OS_Thread_BlkList.Num; index++)
	{
		/** 如果有任务结束阻塞，就将其加入就绪链表。*/
		if((OS_Thread_t *)G_OS_Thread_BlkList.Node[index] == thread)
		{
			((OS_Thread_t) *G_OS_Thread_RdyList.Node[index]) -> Status = OS_THREAD_READY;
			G_OS_Thread_RdyList.Node[G_OS_Thread_RdyList.Num++] = G_OS_Thread_BlkList.Node[index];
			G_OS_Thread_BlkList.Node[index] = OS_NULL;
			G_OS_Thread_BlkList.Num -= 1;
			OS_EXIT_CRITICAL();
			return OS_OK;	
		}
	}

	OS_EXIT_CRITICAL();
	return OS_NOK;
}


/**
 * @brief     删除一个线程，可以是自身，也可以是其他线程。
 * @details   Delete a process. This process can be itself or other threads.
 * @param[in] thread 线程指针句柄。
 * @return    [OS_OK]  线程删除成功。 The thread is deleted successfully.
 * @return    [OS_NOK] 线程删除失败。 The thread delete failed.
 * @note      如果删除自身，那么将会触发一次任务调度。
 *            If you delete itself, it will trigger a task schedule
**/
os_err_t OS_Thread_Delete_Static(OS_Thread_t *thread)
{
	os_uint8_t index = 0;
	
	if( (*G_OS_Thread_RunNode) -> Entry == OS_Idle_Thread) 
	{
		OS_Exce_Handle(EXC_CODE_ILL_CALL_API);
	}
	
	OS_ENTER_CRITICAL();
	if(thread == OS_THREAD_SELF) thread = G_OS_Thread_RunNode;
	
	switch((*thread) -> Status)
	{
		case OS_THREAD_READY:
		{
			/** 删除链表节点。Delete linked list node. */
			for(index = 0; index < OS_THREAD_MAX_NUM; index++)
			{
				if(thread == (OS_Thread_t *)G_OS_Thread_RdyList.Node[index])
				{
					G_OS_Thread_RdyList.Node[index] =                      \
						G_OS_Thread_RdyList.Node[--G_OS_Thread_RdyList.Num];                             
					G_OS_Thread_RdyList.Node[G_OS_Thread_RdyList.Num] = OS_NULL;
					break;
				}
			}
			
		}
		case OS_THREAD_SLEEP:
		{
			/** 删除链表节点。Delete linked list node. */
			for(index = 0; index < OS_THREAD_MAX_NUM; index++)
			{
				if(thread == G_OS_Thread_SlpList.Node[index])
				{
					G_OS_Thread_SlpList.Node[index] =                      \
						G_OS_Thread_SlpList.Node[--G_OS_Thread_SlpList.Num]; 
					G_OS_Thread_SlpList.Node[G_OS_Thread_SlpList.Num] = OS_NULL;
					break;
				}
			}
			break;
		}
		case OS_THREAD_BLOCK:
		{
			/** 删除链表节点。Delete linked list node. */
			for(index = 0; index < OS_THREAD_MAX_NUM; index++)
			{
				if(thread == G_OS_Thread_BlkList.Node[index])
				{
					G_OS_Thread_BlkList.Node[index] =                      \
						G_OS_Thread_BlkList.Node[--G_OS_Thread_BlkList.Num];      
					G_OS_Thread_BlkList.Node[G_OS_Thread_BlkList.Num] = OS_NULL;
					break;
				}
			}
			break;
		}
		case OS_THREAD_RUNNING:
		{
			OS_Free(thread);
			G_OS_Thread_RunNode = OS_NULL;
			OS_EXIT_CRITICAL();
			OS_Thread_Schedule();
		}
		default: OS_EXIT_CRITICAL(); return OS_NOK;
	}
	
	OS_Free(thread);
	OS_EXIT_CRITICAL();
	return OS_OK;
}


/**
 * @brief     删除一个线程，可以是自身，也可以是其他线程。
 * @details   Delete a process. This process can be itself or other threads.
 * @param[in] thread  线程指针句柄。
 * @param[in] stkAddr 线程堆栈指针。 
 * @return    [OS_OK]  线程删除成功。 The thread is deleted successfully.
 * @return    [OS_NOK] 线程删除失败。 The thread delete failed.
 * @note      如果删除自身，那么将会触发一次任务调度。
 *            If you delete itself, it will trigger a task schedule
**/
os_err_t OS_Thread_Delete(OS_Thread_t *thread,OS_Thread_Stk **stkAddr)
{
	return (OS_Free(stkAddr) && OS_Thread_Delete_Static(thread));
}
/*------------------------------------------------------------------------
|                    END OF FLIE.  (C) COPYRIGHT zeweni                  |
------------------------------------------------------------------------*/